package org.ztuffaha.amqsecurity;

/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.Iterator;
import java.util.List;
import java.io.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.FileSystemResource;

import java.util.ListIterator;

/**
 * User: ztuffaha
 * Date: May 22, 2008
 * Time: 4:06:43 PM
 */
public class Reloader extends Thread
{
    private static final Log LOG = LogFactory.getLog(Reloader.class);

    AuthenticationMap mapTemp = new AuthenticationMap();

    boolean firstTime = true;
    private final String encryptionScheme = StringEncrypter.DESEDE_ENCRYPTION_SCHEME;
    private final String fileName;
    private final int scanTimeInSeconds;

    public Reloader(AuthenticationMap map, String filename, int scanTimeInSeconds)
    {
        mapTemp = map;
        this.fileName = filename;
        this.scanTimeInSeconds = scanTimeInSeconds;
    }

    public void run()
    {
        try
        {
            File securityFile = new File(fileName);
            LOG.info("File is being watched o-o");
            long lastModified = securityFile.lastModified();

            while (true)
            {
                try
                {
                    long lastModifiedCurrent = securityFile.lastModified();
                    if (lastModifiedCurrent != lastModified || firstTime)
                    {
                        LOG.info("Change in Security Realm is detected");
                        firstTime = false;
                        mapTemp.cleanQueues();
                        mapTemp.cleanUsers();
                        XmlBeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource(securityFile));
                        AuthList authList = (AuthList) beanFactory.getBean("AuthList");
                        List myAuthList = authList.getEntries();
                        for (int i = 0; i < myAuthList.size(); i++)
                        {
                            AuthEntry user = (AuthEntry) myAuthList.get(i);
                            mapTemp.addAuthEntry(user.getName(), user);
                        }
                        List myQueueList = authList.getQueues();
                        for (int i = 0; i < myQueueList.size(); i++)
                        {
                            QueueEntry queue = (QueueEntry) myQueueList.get(i);
                            mapTemp.addQueueEntry(queue.getQueuename(), queue);
                        }
                        mapTemp.updateMaps();
                        writeUsersXml();

                        lastModified = securityFile.lastModified();
                        lastModifiedCurrent = securityFile.lastModified();
                    }
                    Thread.sleep(1000 * scanTimeInSeconds);
                }
                catch (Exception e)
                {
                    e.printStackTrace(); 
                }
            }

        }
        catch (Exception e)
        {
        	e.printStackTrace();
        }
    }

    public void writeUsersXml()
    {
        StringBuffer buff = new StringBuffer();
        StringBuffer buffUsers = new StringBuffer();
        StringBuffer buffQueues = new StringBuffer();

        buff.setLength(0);
        buff.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?> " +
                "\n<!DOCTYPE beans PUBLIC \"-//SPRING//DTD BEAN//EN\" \"http://www.springframework.org/dtd/spring-beans.dtd\">");
        buff.append("\n<beans>\n\t<bean id=\"AuthList\" class=\"com.isone.activemq.AuthList\">");
        buff.append("\n\t\t<property name=\"entries\">\n\t\t\t<list>");

        List userList = mapTemp.getAllUsres();
        ListIterator userIterator = userList.listIterator();
        int i = 1;
        while (userIterator.hasNext())
        {
            String userName = (String) userIterator.next();
            buff.append("\n\t\t\t\t<ref bean=\"" + "User" + i + "\"/>");
            buffUsers.append("\n\t<bean id = \"User" + i + "\"" + " class=\"com.isone.activemq.AuthEntry\" >");
            buffUsers.append("\n\t\t<property name = \"name\" >");
            buffUsers.append("\n\t\t\t<value >" + userName + "</value >\n\t\t</property>");
            buffUsers.append("\n\t\t<property name = \"password\" >");
            AuthEntry auth = (AuthEntry) mapTemp.getAuthEntry(userName);
            try
            {
                StringEncrypter encrypter = new StringEncrypter(encryptionScheme);

                String encryptedPassword = encrypter.encrypt(auth.getPassword());
                auth.setEncrypted("true");

                buffUsers.append("\n\t\t\t<value >" + encryptedPassword + "</value >");
                buffUsers.append("\n\t\t</property>");
                buffUsers.append("\n\t\t<property name = \"encrypted\" >");
                buffUsers.append("\n\t\t\t<value >" + auth.getEncrypted() + "</value >");
                buffUsers.append("\n\t\t</property>");

                buffUsers.append("\n\t</bean>");
            }
            catch (StringEncrypter.EncryptionException e)
            {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
            i++;
        }
        buff.append("\n\t\t\t</list >\n\t\t</property >");
        buff.append("\n\t\t<property name = \"queues\" >\n\t\t\t<list >");

        List queueList = mapTemp.getAllQueues();
        ListIterator queueListItr = queueList.listIterator();
        int q = 1;
        while (queueListItr.hasNext())
        {
            String queueName = (String) queueListItr.next();
            buff.append("\n\t\t\t\t<ref bean=\"" + "Queue" + q + "\"/>");
            buffQueues.append("\n\t<bean id = \"Queue" + q + "\"" + " class=\"com.isone.activemq.QueueEntry\" >");
            buffQueues.append("\n\t\t<property name = \"queuename\" >");
            buffQueues.append("\n\t\t\t<value >" + queueName + "</value >\n\t\t</property >");
            QueueEntry queue = (QueueEntry) mapTemp.getQueueEntry(queueName);
            buffQueues.append("\n\t\t<property name = \"admins\" >");
            buffQueues.append("\n\t\t\t<value >" + queue.getAdmins() + "</value >\n\t\t</property >");

            buffQueues.append("\n\t\t<property name = \"receivers\" >");
            buffQueues.append("\n\t\t\t<value >" + queue.getReceivers() + "</value >\n\t\t</property >");

            buffQueues.append("\n\t\t<property name = \"senders\" >");
            buffQueues.append("\n\t\t\t<value >" + queue.getSenders() + "</value >\n\t\t</property >");

            buffQueues.append("\n\t</bean>");

            q++;

        }
        buff.append("\n\t\t\t</list >\n\t\t</property >\n\t</bean>");
        StringBuffer finalBuff = new StringBuffer();
        finalBuff.append(buff.toString() + buffUsers.toString() + buffQueues.toString() + "\n</beans >");
        writeUsersXmlFileToDisk(finalBuff.toString());
    }

    public boolean writeUsersXmlFileToDisk(String contents)
    {
        try
        {
            File securityFile = new File(fileName);
            if (securityFile.exists())
            {
                securityFile.delete();
            }
            FileWriter resultsFile = new FileWriter(securityFile, true);
            resultsFile.write(contents);
            resultsFile.close();
            return true;
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return false;
        }
    }
}
